package com.common.web.controller;

import java.beans.PropertyEditorSupport;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;

import org.apache.commons.lang3.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SimpleDateFormatSerializer;
import com.common.base.config.Global;
import com.common.base.persistence.Page;
import com.common.base.utils.BeanValidators;
import com.common.base.utils.CookieUtils;
import com.common.base.utils.DateUtils;
import com.common.utils.StringUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 控制器支持类
 * @author jfeng
 * @version 2014-03-07
 */
public abstract class BaseController{
	protected String message;
	protected Boolean isSuccess;
	
	/**
	 * 日志对象
	 */
	protected Logger logger = LoggerFactory.getLogger(getClass());
	
	/**
	 * 验证Bean实例对象
	 */
	@Autowired
	protected Validator validator;
	
	protected ObjectMapper mapper = new ObjectMapper();
	/**
	 * 服务端参数有效性验证
	 * @param object 验证的实体对象
	 * @param groups 验证组
	 * @return 验证成功：返回true；严重失败：将错误信息添加到 message 中
	 */
	protected boolean beanValidator(Model model, Object object, Class<?>... groups) {
		try{
			BeanValidators.validateWithException(validator, object, groups);
		}catch(ConstraintViolationException ex){
			List<String> list = BeanValidators.extractPropertyAndMessageAsList(ex, ": ");
			list.add(0, "数据验证失败：");
			addMessage(model, false, list.toArray(new String[]{}));
			return false;
		}
		return true;
	}
	
	/**
	 * 服务端参数有效性验证
	 * @param object 验证的实体对象
	 * @param groups 验证组
	 * @return 验证成功：返回true；严重失败：将错误信息添加到 flash message 中
	 */
	protected boolean beanValidator(RedirectAttributes redirectAttributes, Object object, Class<?>... groups) {
		try{
			BeanValidators.validateWithException(validator, object, groups);
		}catch(ConstraintViolationException ex){
			List<String> list = BeanValidators.extractPropertyAndMessageAsList(ex, ": ");
			list.add(0, "数据验证失败：");
			addMessage(redirectAttributes, false, list.toArray(new String[]{}));
			return false;
		}
		return true;
	}
	
	/**
	 * 添加Model消息
	 * @param message
	 */
	protected void addMessage(Model model, String... messages) {
		StringBuilder sb = new StringBuilder();
		for (String message : messages){
			sb.append(message).append(messages.length>1?"<br/>":"");
		}
		model.addAttribute("message", sb.toString());
		model.addAttribute("isSuccess", true);
	}
	
	/**
	 * 添加ajax消息
	 * @param messages
	 */
	protected void addMessage(String... messages) {
		StringBuilder sb = new StringBuilder();
		for (String message : messages){
			sb.append(message).append(messages.length>1?"<br/>":"");
		}
		this.message = sb.toString();
		this.isSuccess = true;
	}
	
	/**
	 * 添加Flash消息
	 * @param message
	 */
	protected void addMessage(RedirectAttributes redirectAttributes, String... messages) {
		StringBuilder sb = new StringBuilder();
		for (String message : messages){
			sb.append(message).append(messages.length>1?"<br/>":"");
		}
		redirectAttributes.addFlashAttribute("message", sb.toString());
		redirectAttributes.addFlashAttribute("isSuccess", true);
	}
	/**
	 * 添加Model消息
	 * @param message
	 */
	protected void addMessage(Model model, Boolean isSuccess, String... messages) {
		StringBuilder sb = new StringBuilder();
		for (String message : messages){
			sb.append(message).append(messages.length>1?"<br/>":"");
		}
		model.addAttribute("message", sb.toString());
		model.addAttribute("isSuccess", isSuccess);
	}
	
	/**
	 * 添加ajax消息
	 * @param messages
	 */
	protected void addMessage(Boolean isSuccess, String... messages) {
		StringBuilder sb = new StringBuilder();
		for (String message : messages){
			sb.append(message).append(messages.length>1?"<br/>":"");
		}
		this.message = sb.toString();
		this.isSuccess = isSuccess;
	}
	
	/**
	 * 添加Flash消息
	 * @param message
	 */
	protected void addMessage(RedirectAttributes redirectAttributes, Boolean isSuccess, String... messages) {
		StringBuilder sb = new StringBuilder();
		for (String message : messages){
			sb.append(message).append(messages.length>1?"<br/>":"");
		}
		redirectAttributes.addFlashAttribute("message", sb.toString());
		redirectAttributes.addFlashAttribute("isSuccess", isSuccess);
	}
	
	/**
	 * 初始化数据绑定
	 * 1. 将所有传递进来的String进行HTML编码，防止XSS攻击
	 * 2. 将字段中Date类型转换为String类型
	 */
	@InitBinder
	protected void initBinder(WebDataBinder binder) {
		this.message = new String();
		// String类型转换，将所有传递进来的String进行HTML编码，防止XSS攻击
		binder.registerCustomEditor(String.class, new PropertyEditorSupport() {
			@Override
			public void setAsText(String text) {
				setValue(text == null ? null : StringEscapeUtils.escapeHtml4(text.trim()));
			}
			@Override
			public String getAsText() {
				Object value = getValue();
				return value != null ? value.toString() : "";
			}
		});
		// Date 类型转换
		binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
			@Override
			public void setAsText(String text) {
				setValue(DateUtils.parseDate(text));
			}
		});
	}
	
	private String defaultJSONString(String message,Boolean isSuccess){
		Map<String, Object> jsonMap = new HashMap<String, Object>();
		//添加消息
		if (this.message != null && !this.message.isEmpty()) {
			jsonMap.put("message", this.message);
		}
		// 添加执行状态
		jsonMap.put("isSuccess", this.isSuccess == null?true:this.isSuccess);
		try {
			return mapper.writeValueAsString(jsonMap);
		} catch (JsonProcessingException e) {
			e.printStackTrace();
		}
		return defaultJSONString(message, isSuccess); 
	}
	
	/**
	 * 控制器操作后返回JSON数据
	 * @param rows
	 * 		数据集
	 * @param total
	 * 		总记录条数
	 * @return
	 */
	protected String toJSONString(List<?> rows, int total) {
		Map<String, Object> jsonMap = new HashMap<String, Object>();
		jsonMap.put("total", total);
		jsonMap.put("rows", rows);
		//添加消息
		if (this.message != null && !this.message.isEmpty()) {
			jsonMap.put("message", this.message);
		}
		//添加执行状态
		jsonMap.put("isSuccess", this.isSuccess == null?true:this.isSuccess);
		try {
			return mapper.writeValueAsString(jsonMap);
		} catch (JsonProcessingException e) {
			e.printStackTrace();
			addMessage(false, StringUtils.getMessage(Global.MSG_SYSTEM_ERROR));
			return defaultJSONString(message, isSuccess);
		}
	}
	
	/**
	 * 控制器操作后返回JSON数据
	 * @param rows
	 * 		数据集
	 * @param total
	 * 		总记录条数
	 * @return
	 */
	protected String toJSONString(Page<?> page) {
		this.isSuccess = true;
		Map<String, Object> jsonMap = new HashMap<String, Object>();
		jsonMap.put("total", page.getCount());
		jsonMap.put("rows", page.getList());
		//添加消息
		if (this.message != null && !this.message.isEmpty()) {
			jsonMap.put("message", this.message);
		}
		//添加执行状态
		jsonMap.put("isSuccess", this.isSuccess == null?true:this.isSuccess);
		try {
			SerializeConfig mapping = new SerializeConfig();
			mapping.put(Timestamp.class, new SimpleDateFormatSerializer("yyyy-MM-dd HH:mm:ss"));
			//会对相同对象使用引用标记以节省字符串体积，会有$ref 
			String s = JSON.toJSONString(jsonMap, mapping); // 转化为Json字符串
			//避免了$ref，但是内容增大，在人员列表查询中报内存溢出
//			String s = JSON.toJSONString(jsonMap, SerializerFeature.DisableCircularReferenceDetect);
			return s;
		} catch (Exception e) {
			e.printStackTrace();
			addMessage(false, StringUtils.getMessage(Global.MSG_SYSTEM_ERROR));
			return defaultJSONString(message, isSuccess);
		}
	}
	
	protected String zuiToJsonString(Page<?> page){
		this.isSuccess = true;
		Map<String, Object> jsonMap = new HashMap<String, Object>();
		jsonMap.put("total", page.getCount());
		jsonMap.put("rows", page.getList());
		//添加消息
		if (this.message != null && !this.message.isEmpty()) {
			jsonMap.put("message", this.message);
		}
		//添加执行状态
		jsonMap.put("isSuccess", this.isSuccess == null?true:this.isSuccess);
		try {//jackson
			ObjectMapper mapper = new ObjectMapper();
			String s = mapper.writeValueAsString(jsonMap);
			return s;
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
			addMessage(false, StringUtils.getMessage(Global.MSG_SYSTEM_ERROR));
			return defaultJSONString(message, isSuccess);
		}
	}
	
	class MeDate{
		private Object birthday;
		
		public Object getBirthday() {
			return birthday;
		}
		public void setBirthday(Object birthday) {
			this.birthday = birthday;
		}
	}
	
	/**
	 * 控制器操作后返回JSON数据
	 * @param data
	 * 		数据对象
	 * @return
	 */
	protected String toJSONString(Object data){
		JSONObject json = new JSONObject();
		if (data == null || data.toString().isEmpty()) {
			
		}else{
			try{
				json = JSONObject.parseObject(mapper.writeValueAsString(data));
			}catch(Exception e){
				e.printStackTrace();
				addMessage(false, StringUtils.getMessage(Global.MSG_SYSTEM_ERROR));
				return defaultJSONString(message, isSuccess); 
			}
		}
		//添加消息
		if (this.message != null && !this.message.isEmpty()) {
			json.put("message", this.message);
		}
		// 添加执行状态
		json.put("isSuccess", this.isSuccess == null?true:this.isSuccess);
		return json.toJSONString();
	}
	
	/**
	 * 控制器操作后返回JSON数据
	 * @param data
	 * 		数据对象
	 * @return
	 */
	protected String toJSONString(List<?> data){
		try {
			return mapper.writeValueAsString(data);
		} catch (JsonProcessingException e) {
			e.printStackTrace();
			addMessage(false, StringUtils.getMessage(Global.MSG_SYSTEM_ERROR));
			return defaultJSONString(message, isSuccess);
		}
	}
	
	/**
	 * 返回模型和视图
	 * @param viewName
	 * 		视图名称
	 * @param request
	 * @param response
	 * @param model
	 * @return
	 */
	protected ModelAndView toModelAndView(String viewName, HttpServletRequest request, HttpServletResponse response, Model model) {
		/**
		 * 从cookie读取theme
		 * 默认为default
		 */
		String theme = CookieUtils.getCookie(request, CookieUtils.THEME_COOKIE);
		theme = theme == null ? Global.getDefaultTheme() : theme;
		model.addAttribute("theme", theme);
		return new ModelAndView(viewName);
	}
	
	/**
	 * 返回模型和视图
	 * @param viewName
	 * @param request
	 * @param response
	 * @param model
	 * @return
	 */
	protected ModelAndView toModelAndView(View view, HttpServletRequest request, HttpServletResponse response, Model model) {
		/**
		 * 从cookie读取theme
		 * 默认为default
		 */
		String theme = CookieUtils.getCookie(request, CookieUtils.THEME_COOKIE);
		theme = theme == null ? Global.getDefaultTheme() : theme;
		model.addAttribute("theme", theme);
		return new ModelAndView(view);
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public Boolean getIsSuccess() {
		return isSuccess;
	}

	public void setIsSuccess(Boolean isSuccess) {
		this.isSuccess = isSuccess;
	}

	public Validator getValidator() {
		return validator;
	}

	public void setValidator(Validator validator) {
		this.validator = validator;
	}
	
}
